//
//  ServerController.h
//  Memento 3.0
//
//  Created by Chris Maddocks on 10-08-01.
//  Copyright 2010 Team Memento. All rights reserved.
//
//  Portions adapted from SpeakHereController.h; see http://developer.apple.com/iphone/library/samplecode/SpeakHere/Listings/Classes_SpeakHereController_mm.html#//apple_ref/doc/uid/DTS40007802-Classes_SpeakHereController_mm-DontLinkElementID_20
//
//  Description: This class mediates between a PhotoCollection and an external Memento Server.  It supports user authentication,
//  catalog listing, catalog uploading, and retrieval or storage of individual memory components (photo or audio).
//  Please see the Memento Server design document for details on the communications protocol used.
//
//  10-08-03: Add ServerControllerDelegate protocol for relaying progress  (C. Maddocks)
//  10-08-01: Initial creation (C. Maddocks)

#import "ServerController.h"
#import "Memory.h"
#import "PhotoCollection.h"
#import "ASIFormDataRequest.h"


@implementation ServerController
@synthesize photoCollection, serverURL, delegate;

- (id)initWithURL:(NSURL *)url usingPhotoCollection:(PhotoCollection *)aPhotoCollection delegate:(NSObject *)aDelegate{
	self.serverURL = url;
	self.photoCollection = aPhotoCollection;
	self.delegate = aDelegate;
	return self;
}

#pragma mark -
#pragma mark User account and session management

- (BOOL)authenticateUser:(NSString *)username withPassword:(NSString *)password usingScript:(NSString *)script {
	NSURL *createUserURL = [[NSURL alloc] initWithString:script relativeToURL:serverURL];
	
	ASIFormDataRequest *request = [ASIFormDataRequest requestWithURL:createUserURL];
	[createUserURL release];
	
	[request setPostValue:username forKey:@"username"];
	[request setPostValue:password forKey:@"password"];
	[request startSynchronous];
	
	NSError *error = [request error];
	if (!error) {
		NSString *responseString = [request responseString];
		NSArray *response = [responseString componentsSeparatedByString:@"\n"];
		
		if ([[response objectAtIndex:0] isEqualToString:@"1"]) {
			sessionToken = [(NSString *)[response objectAtIndex:1] retain];
			return true;
		} else return false;
	} else return false;
}

- (BOOL)createUser:(NSString *)username withPassword:(NSString *)password {
	return [self authenticateUser:username withPassword:password usingScript:@"create_user.php"];
}

- (BOOL)loginWithUsername:(NSString *)username withPassword:(NSString *)password {
	if ([self authenticateUser:username withPassword:password usingScript:@"authenticate.php"]) {
		return true;
	} else {
		return [self createUser:username withPassword:password];
	} 		
}

#pragma mark -
#pragma mark Storage and retrieval (interface points)

- (void)retrieveMemories {
	[self.photoCollection clearCollection];
	
	NSArray *data = [self retrieveMemoryList];
	int count = [data count];
	int n = 0;
	
	if ([self.delegate respondsToSelector:@selector(progressChanged:ofMaximum:)]) {
		[delegate progressChanged:n ofMaximum:count];
	}
	
	for (NSNumber *memoryId in data) {
		Memory *memory = [self retrieveMemory:[memoryId intValue]];
		[self.photoCollection addMemory:memory];
		
		if ([self.delegate respondsToSelector:@selector(progressChanged:ofMaximum:)]) {
			[delegate progressChanged:++n ofMaximum:count];
		}
	}
}

- (int)backupMemories {
	int errors = 0;
	BOOL result = NO;
	BOOL shouldContinue = [photoCollection count] > 0;
	
	[self clearCollection];
	
	int prevIndex = [photoCollection currentIndex];
	
	int count = [photoCollection count];
	int n = 0;
	
	if ([self.delegate respondsToSelector:@selector(progressChanged:ofMaximum:)]) {
		[delegate progressChanged:n ofMaximum:count];
	}
	
	[photoCollection moveFirst];
	while (shouldContinue) {
		NSLog(@"Sending memory %d to backup server", [photoCollection currentMemory].memoryId);
		result = [self uploadMemory:[photoCollection currentMemory]];
		if (!result) errors++;
		
		if ([self.delegate respondsToSelector:@selector(progressChanged:ofMaximum:)]) {
			[delegate progressChanged:++n ofMaximum:count];
		}
		
		shouldContinue = [photoCollection moveNext];  // returns FALSE if we try to move past EOF
	}

	[photoCollection setCurrentIndex:prevIndex];  // Return user to memory they were previously looking at
	
	return errors;
	
}

#pragma mark -
#pragma mark Storage and retrieval (supporting functions)

- (BOOL)uploadMemory:(Memory *)memory {
	NSURL *url = [[NSURL alloc] initWithString:@"store.php" relativeToURL:serverURL];
	
	ASIFormDataRequest *request = [ASIFormDataRequest requestWithURL:url];
	[url release];
	
	[request setPostValue:sessionToken forKey:@"session_token"];
	[request setPostValue:[NSNumber numberWithInt:memory.memoryId] forKey:@"memory_id"];
	[request setPostValue:memory.dateTime forKey:@"memory_time"];
	[request setPostValue:[NSNumber numberWithDouble:memory.location.latitude] forKey:@"latitude"];
	[request setPostValue:[NSNumber numberWithDouble:memory.location.longitude] forKey:@"longitude"];

	if (memory.imageFile != nil) {
		[request setFile:[[photoCollection collectionDataPath] stringByAppendingPathComponent:memory.imageFile] forKey:@"image_file"];		
	}

	if (memory.audioFile != nil) {
		[request setFile:[[photoCollection collectionDataPath] stringByAppendingPathComponent:memory.audioFile] forKey:@"audio_file"];		
	}

	[request startSynchronous];
	
	NSError *error = [request error];
	if (!error) {
		NSString *responseString = [request responseString];
		NSArray *response = [responseString componentsSeparatedByString:@"\n"];
		
		if ([[response objectAtIndex:0] isEqualToString:@"1"]) {
			return true;
		} else return false;
	} else return false;
	
}

- (NSArray *)retrieveMemoryList {
	NSURL *url = [[NSURL alloc] initWithString:@"list.php" relativeToURL:serverURL];
	ASIFormDataRequest *request = [ASIFormDataRequest requestWithURL:url];
	[url release];
	
	[request setPostValue:sessionToken forKey:@"session_token"];
	[request startSynchronous];
	
	NSError *error = [request error];
	if (!error) {
		NSString *responseString = [request responseString];
		NSArray *response = [responseString componentsSeparatedByString:@"\n"];
		
		if (([[response objectAtIndex:0] isEqualToString:@"1"]) && ([response count] > 1)) {
			NSMutableArray *memories = [[NSMutableArray alloc] initWithArray:response];
			[memories removeObjectAtIndex:0];  // Remove success/failure string
			[memories removeObjectAtIndex:[memories count]-1];  // Remove last entry, invalid but implied by newline
			return [memories autorelease];
		} else return nil;
	} 
	
	return nil;	
}


- (BOOL)clearCollection {
	NSURL *url = [[NSURL alloc] initWithString:@"empty_collection.php" relativeToURL:serverURL];
	ASIFormDataRequest *request = [ASIFormDataRequest requestWithURL:url];
	[url release];
	
	[request setPostValue:sessionToken forKey:@"session_token"];
	[request startSynchronous];
	
	NSError *error = [request error];
	if (!error) {
		NSString *responseString = [request responseString];
		NSArray *response = [responseString componentsSeparatedByString:@"\n"];
		
		return [[response objectAtIndex:0] isEqualToString:@"1"];
	} else {
		return FALSE;	
	}
}


- (Memory *)retrieveMemory:(int)memoryId {
	// Retrieve memory metadata
	NSString *relativeURL = [[NSString alloc] initWithFormat:@"retrieve.php?session_token=%@&memory_id=%d&component=%d", sessionToken, memoryId, kComponentMetadata];
	
	NSURL *url = [[NSURL alloc] initWithString:relativeURL relativeToURL:self.serverURL];
	NSDictionary *data = [[NSDictionary alloc] initWithContentsOfURL:url];
	
	Memory *memory = [[Memory alloc] initWithDictionary:data];

	[data release];
	[url release];
	[relativeURL release];
	
	
	// Retrieve image and audio
	memory.imageFile = [self retrieveComponent:kComponentImage forMemory:memory];
	memory.audioFile = [self retrieveComponent:kComponentAudio forMemory:memory];
	
	return [memory autorelease];	
}


- (NSString *)retrieveComponent:(int)component forMemory:(Memory *)memory {
	if ((component != kComponentImage) && (component != kComponentAudio)) {
		return nil;	
	}
	
	NSURL *url = [[NSURL alloc] initWithString:@"retrieve.php" relativeToURL:serverURL];
	
	ASIFormDataRequest *request = [ASIFormDataRequest requestWithURL:url];
	[url release];
	
	[request setPostValue:sessionToken forKey:@"session_token"];
	[request setPostValue:[NSNumber numberWithInt:memory.memoryId] forKey:@"memory_id"];
	[request setPostValue:[NSNumber numberWithInt:component] forKey:@"component"];
	
	[request startSynchronous];
	
	NSError *error = [request error];
	if (!error) {
		NSData *data = [[request responseData] retain];
		if ([data length] == 0) return nil;
		
		NSString *filename = [[memory generateFileNameWithExt:(component == kComponentImage ? @"jpg" : @"caf")] retain];
		NSString *filePath = [[self.photoCollection collectionDataPath] stringByAppendingPathComponent:filename];
		[data writeToFile:filePath atomically:YES];
		[data release];
		
		return [filename autorelease];
	} else return nil;	
}


@end
